
(function(window){

    var shl = function(){
        var argv = shl.arguments;
        var argc = argv.length;
        var args = [];

        for(var i = 0; i < argc; i++){
            args[args.length] = argv[i];
            alert(argv[i]);
        }
        return new shl.fn.init(args);
    }

    var inner;
    // ----------------------- s: building super html obj
    inner.basic = {
        _object_size: function (obj){
            var len = 0;
            if(typeof(obj) == 'object'){
                for(var i in obj){
                    if(typeof(obj) != 'function'){
                        len ++;
                    }
                }
            }
            return len;
        }
        ,
        _is_word_char:function (c){
            var code = c.charCodeAt(0);
            return(code >= 65 && code <= 90) || (code >= 97 && code <= 122) ||
            (code >= 48 && code <= 57) || c == '_';
        }
        ,
        _is_space_char: function (c){
            return c == ' ' || c == '\n' || c == '\t';
        }
        ,
        _is_integer: function (s){
            return s == parseInt(s);
        }
        ,
        /**
         * @param curr
         * str | ptr
         */
        _get_word: function (curr){
            var r = [];

            for(var strlen = curr.str.length; curr.ptr < strlen; curr.ptr ++){
                var c = curr.str.charAt(curr.ptr);
                if(inner.basic._is_word_char(c)){
                    r[r.length] = c;
                } else {
                    return r.join('');
                }
            }

            return r.join('');
        }
        ,
        _escape_for_html: function (s){
            return htmlentities(s);
        }
        ,
        _escape_for_attr: function (s){
            return s.toString().split('\'').join('\\\'');
        }
        ,
        _get_value_for_var: function (vtype, value, isAttr){
            isAttr = setDefault(isAttr, true);

            if(value === null){
                return null;
            }
            if(vtype == 's'){
                if(isArray(value)){
                    if(isAttr){
                        value = value.join('');
                    } else{
                        value = value.join('\n');
                    }
                }
                if(isAttr){
                    return inner.basic._escape_for_attr(value);
                } else {
                    return inner.basic._escape_for_html(value);
                }
            } else if (vtype == 'd'){
                if(isArray(value)){
                    return null;
                }
                return parseInt(value);
            } else if(vtype == 'f'){
                if(isArray(value)){
                    return null;
                }
                return parseFloat(value);
            } else if(vtype == 'ne'){
                if(isArray(value)){
                    if(isAttr){
                        return value.join('');
                    } else {
                        return value.join('\n');
                    }
                }
                return value;
            } else {
                return null;
            }
        }
        ,
        _get_until_not_char: function (curr, cond){
            var r = [];
            for(var l = curr.str.length; curr.ptr < l; curr.ptr ++){
                var c = curr.str.charAt(curr.ptr);
                if(c == cond){
                    r[r.length] = c;
                } else {
                    break;
                }
            }

            return r.join('');
        }
        ,
        _get_until_char: function (curr, cond){
            var r = [];
            for(var l = curr.str.length; curr.ptr < l; curr.ptr ++){
                var c = curr.str.charAt(curr.ptr);
                if(c != cond){
                    r[r.length] = c;
                } else {
                    var res = new Object;
                    res['cond'] = true;
                    res['r'] = r.join('');
                    return res;
                }
            }

            res = new Object;
            res['cond'] = false;
            res['r'] = r.join('');
            return res;
        }
        ,
        _get_char_for_attr: function (c){
            if(c == "'"){
                return "\\'";
            } else{
                return c;
            }
        }
        ,
        _if_match_close_cond: function (cond, tag){
            if('tag' in cond && tag['tag'] != cond['tag']){
                return false;
            }
            if('id' in cond && tag['id'] != cond['id']){
                return false;
            }
            if(typeof(cond['class']) == 'object'){
                for(var cls in cond['class']){
                    if(typeof(tag['class']) != 'object'){
                        return false;
                    }
                    if(!(cls in tag['class'])){
                        return false;
                    }
                }
            }
            if('hidden' in cond && tag['hidden'] != cond['hidden']){
                return false;
            }
            ddebug('cond', cond, 'tag', tag);
            return true;
        }
        ,
        _skip_all_space:   function (curr){
            var l = curr.str.length;
            while(curr.ptr < l){
                var c = curr.str.charAt(curr.ptr);
                if(!inner.basic._is_space_char(c)){
                    return c;
                }
                curr.ptr ++;
            }
            return false;
        }
    }

    inner.parser = {
        _parse_shl_code: function (compiledInstr, currAry, shObj, indentation, newline){
            var currAryPtr = 0;
            var currAryLength = currAry.length;
            while(currAryPtr < currAryLength){
                var curr = {
                    str:currAry[currAryPtr],
                    ptr:0
                };


                if(typeof(curr.str) != 'object'){
                    var strLen = curr.str.length;
                    while(curr.ptr < strLen){
                        var c = curr.str.charAt(curr.ptr);
                        if(inner.basic._is_word_char(c)){
                            // --------------- tag, attr, for|if --------------
                            var res = inner.basic._parse_char(curr);
                            if(res === false){
                                return "Error @ '" + curr.str + "' #1";
                            }
                            if(res['type'] == 'attr' || res['type'] == 'if'){
                                if(!('f' in res)){
                                    if(res['name'] == '' || !('name' in res)){
                                        res['content'] = inner.basic._get_value_for_var(res['vtype'], currAry[++currAryPtr], true);
                                    } else {
                                        res['content'] = inner.basic._get_value_for_var(res['vtype'], shObj[res['name']], true);
                                    }
                                } else {
                                    res['content'] = inner.basic._get_value_for_var('ne', res['content'], true);
                                }
                            }
                            compiledInstr[compiledInstr.length] = res;
                        } else if(c == ':'){
                            // ------------- html ---------------
                            curr.ptr ++;
                            res = inner.basic._parse_attr(curr);
                            if(res === false){
                                return "Error @'" + curr.str + "' #2";
                            }
                            res['type'] = 'html';
                            if(!('f' in res)){
                                if(res['name'] == '' || !('name' in res)){
                                    res['content'] = inner.basic._get_value_for_var(res.vtype, currAry[++currAryPtr], false);
                                } else {
                                    res['content'] = inner.basic._get_value_for_var(res['vtype'], shObj[res['name']], false);
                                }
                            } else {
                                res['content'] = inner.basic._get_value_for_var('ne', res['content'], false);
                            }
                            ddebug(res);
                            compiledInstr[compiledInstr.length] = res;
                        } else if(c == '/'){
                            // ------------------ template var || //efor || //eif--------------------
                            c = curr.str.charAt(++curr.ptr);
                            if(inner.basic._is_word_char(c)){
                                var w = inner.basic._get_word(curr);
                                if(w != ''){
                                    res = {
                                        type:'html'
                                    };
                                    if(w in shObj){
                                        res['content'] = shHtml(shObj[w]);
                                    }
                                    compiledInstr[compiledInstr.length] = res;
                                } else {
                                    return "Error @ '" + curr.str + "' #3";
                                }
                            } else if (c == '/'){
                                curr.ptr++;
                                w = inner.basic._get_word(curr);
                                if(w == 'efor' || w == 'eif'){
                                    res = {
                                        type: w
                                    };
                                    compiledInstr[compiledInstr.length] = res;
                                } else {
                                    return "Error @ '" + curr.str + "' #4";
                                }
                            } else {
                                return "Error @ '" + curr.str + "' #5";
                            }
                        } else if(c == '&'){
                            // ----------------- quick html ------------------
                            curr.ptr ++;
                            var quickHtml = inner.basic._get_until_char(curr, '&');
                            curr.ptr ++;
                            if(quickHtml['cond']){
                                res = {
                                    type:'html',
                                    content: inner.basic._escape_for_html(quickHtml['r'])
                                };
                                compiledInstr[compiledInstr.length] = res;
                            } else {
                                return "Error @ '" + curr.str + "' #6";
                            }
                        } else if(c == '<'){
                            var r = inner.basic._get_until_not_char(curr, '<');
                            res = {
                                type: 'close'
                            };
                            if(r.length == 1){
                                // only one '<'

                                if(inner.basic._is_space_char(curr.str.charAt(curr.ptr)) || curr.ptr == strLen){
                                    res['level'] = 1;
                                } else {
                                    var tmpPtr = curr.ptr;
                                    w = inner.basic._get_word(curr);
                                    if(inner.basic._is_integer(w)){
                                        // if there is a number after <
                                        res['level'] = parseInt(w);
                                    } else {
                                        // if there is a set of closing conditions
                                        // reset the ptr, because the word is not numeric, we need to do it again
                                        curr.ptr = tmpPtr;
                                        r = inner.basic._parse_conditional_close(curr);
                                        if(r != false){
                                            res['cond'] = r;
                                        } else {
                                            return "Error @ '" + curr.str + "' #7";
                                        }
                                    } // e : else
                                } // e: else
                            } else {
                                res['level'] = r.length;
                            }
                            compiledInstr[compiledInstr.length] = res;
                        } else if(inner.basic._is_space_char(c)){
                            curr.ptr ++;
                        } else {
                            return "Error @ '" + curr.str + "' #8";
                        }
                    }
                } else if(curr.str['/shobj'] == 1) {
                    res = {
                        type: 'html',
                        content: shHtml(curr.str, indentation, newline)
                    }
                    compiledInstr[compiledInstr.length] = res;
                } else if (isArray(curr.str)){
                    r = inner.basic._parse_shl_code(compiledInstr, curr.str, shObj, indentation, newline);
                    if(r != null){
                        return r;
                    }
                }
                currAryPtr ++;

                ddebug(currAryPtr < currAryLength, currAryPtr, currAryLength);
            }

            return null;
        }
        ,
        _parse_char:function (curr){
            var w = inner.basic._get_word(curr);
            var c = curr.str.charAt(curr.ptr);

            if(c == '#' || c == '.' || c == '?' || c == '>' || c == '/'){
                var res = inner.parser._parse_tag(curr);
                ddebug(curr.str, 'curr.str');
                if(res === false)
                    return false;
                res['tag'] = w;
                res['type'] = 'tag';
            } else if(c == ':'){
                curr.ptr ++;
                res = inner.basic._parse_attr(curr);
                res['attr'] = w;
                res['type'] = 'attr';
            } else if (c == '('){
                if(w == 'for' || w == 'if'){
                    curr.ptr ++;
                    res = inner.parser._parse_var(curr);
                    ddebug(res, 'for if');
                    if(res === false || (w == 'for' && res['vtype'] != 'ne')){
                        // the return shouldn't be false, and there must be no vtype rather than 'ne' for 'for'
                        return false;
                    }
                    res['type'] = w;

                    if(w == 'for'){
                        c = inner.basic._skip_all_space(curr);
                        if(c != ')'){
                            // there must be no other extra chars than spaces
                            // and a ')' must be met before the string ends
                            return false;
                        }
                    } else {
                        if(!inner.basic._is_space_char(curr.str.charAt(curr.ptr))){
                            return false;
                        }
                        curr.ptr ++;
                        var value = inner.basic._get_until_char(curr, ')');
                        if(value['cond']){
                            res['value'] = $.trim(value['r']);
                        } else {
                            return false;
                        }
                    }
                    curr.ptr ++;
                } else {
                    return false;
                }
            } else {
                return false;
            }

            return res;
        }
        ,
        _parse_var: function (curr){
            var strLen = curr.str.length;
            while (curr.ptr < strLen){
                var c = curr.str.charAt(curr.ptr);

                if(c == '~'){
                    curr.ptr++;
                    var w = inner.basic._get_word(curr);
                    if(w == 's' || w == 'd' || w == 'ne' || w == 'f'){
                        var res = {
                            vtype: w,
                            name: ''
                        }

                        if(curr.str.charAt(curr.ptr) == '/'){
                            curr.ptr++;
                            w = inner.basic._get_word(curr);
                            if(w != ''){
                                res['name'] = w;
                            } else {
                                return false;
                            }
                        }
                        return res;
                    }
                } else if(c == '/'){
                    curr.ptr ++;
                    w = inner.basic._get_word(curr);
                    if(w != ''){
                        res = {
                            vtype: 'ne',
                            name: w
                        }
                        return res;
                    }
                    else {
                        return false;
                    }
                } else if (!inner.basic._is_space_char(c)){
                    return false;
                }

                curr.ptr ++;
            }

            return false;
        }
        ,
        _parse_attr:function (curr, isAttr){
            isAttr = setDefault(isAttr, true);

            var content = new Array;
            var isWaitingForVarDef = true;
            var strLen = curr.str.length;
            while(curr.ptr < strLen){
                var c = curr.str.charAt(curr.ptr);
                if(isWaitingForVarDef && c == '~'){
                    curr.ptr ++;
                    var w = inner.basic._get_word(curr);
                    if(w == 's' || w == 'd' || w == 'ne' || w == 'f'){
                        var res = {
                            vtype: w
                        };
                        if(curr.str.charAt(curr.ptr) == '/'){
                            curr.ptr++;
                            w = inner.basic._get_word(curr);
                            if(w != ''){
                                res['name'] = w;
                            } else {
                                return false;
                            }
                        } else {
                            res['name'] = '';
                        }

                        ddebug('attr raw', res);
                        return res;
                    } else {
                        content[content.length] = '~';
                        if(w != ''){
                            content[content.length] = w;
                        }
                        isWaitingForVarDef = false;
                        continue;
                    }
                } else if (isWaitingForVarDef && c == '/'){
                    curr.ptr++;
                    w = inner.basic._get_word(curr);
                    if(w != ''){
                        res = {
                            vtype: 'ne',
                            name: w
                        };
                        return res;
                    } else {
                        isWaitingForVarDef = false;
                        //                curr.ptr--
                        continue;
                    }
                } else if(c == ','){
                    if(curr.str.charAt(curr.ptr + 1) == ','){
                        curr.ptr += 2;

                        return {
                            content: content.join(''),
                            f: 1
                        };
                    } else {
                        content[content.length] = c;
                    }
                } else if(c == '/'){
                    curr.ptr ++;
                    if(curr.str.charAt(curr.ptr) == ','){
                        content[content.length] = ',';
                    } else {
                        content[content.length] = '/';
                        content[content.length] = curr.str.charAt(curr.ptr);
                    }
                } else if (isWaitingForVarDef){
                    if(!inner.basic._is_space_char(c)){
                        isWaitingForVarDef = false;
                        content[content.length] = c;
                    }
                } else {
                    content[content.length] = c;
                }
                curr.ptr ++;
            }

            res = {
                vtype: 'ne'
            };
            return res;
        }
        ,
        _parse_tag: function (curr){
            var res = {
                content:[]
            };

            var strLen = curr.str.length;
            while(curr.ptr < strLen){
                var c = curr.str.charAt(curr.ptr);
                if(c == '#'){ // id
                    curr.ptr++;
                    var w = inner.basic._get_word(curr);
                    if(w == ''){
                        return false;
                    }
                    res['id'] = w;
                } else if(c == '.'){ // class
                    curr.ptr++;
                    w = inner.basic._get_word(curr);
                    if(w == ''){
                        return false;
                    }
                    res['class'] = res['class'] || {};
                    res['class'][w] = 1;
                } else if (c == '?'){
                    curr.ptr++;
                    w = inner.basic._get_word(curr);
                    if(w == ''){
                        return false;
                    }
                    res['hidden'] = w;
                } else if (c == '>'){
                    curr.ptr ++;
                    var condClose = inner.basic._parse_conditional_close(curr);
                    ddebug(condClose, condClose === false, 'what cond');
                    if(condClose === false){
                        ddebug(curr, 'why');
                        return false;
                    } else if(condClose.length > 0){
                        res['cond'] = condClose;
                    }
                    res['level'] = 'n';
                    return res;
                } else if (c == '/'){
                    curr.ptr ++;
                    res['level'] = 1;
                    return res;
                } else{
                    // syntax error, return false
                    return false;
                }
            }

            return false;
        }
        ,
        _parse_conditional_close:function (curr){
            var conds = [];
            var w = inner.basic._get_word(curr);
            var res = {};

            if(w != ''){
                res['tag'] = w;
            }

            var strLen = curr.str.length;
            while(curr.ptr < strLen){
                var c = curr.str.charAt(curr.ptr);
                ddebug(c, 'c');
                if(c == '#'){ // id
                    curr.ptr ++;
                    w = inner.basic._get_word(curr);

                    if(w == ''){
                        return false;
                    }
                    res['id'] = w;
                } else if(c == '.'){ // class
                    curr.ptr ++;
                    w = inner.basic._get_word(curr);

                    if(w == ''){
                        return false;
                    }
                    res['class'] = res['class'] || {};
                    res['class'][w] = 1;
                    ddebug(res);
                } else if(c == '?'){
                    curr.ptr ++;
                    w = inner.basic._get_word(curr);

                    if(w == ''){
                        return false;
                    }
                    res['hidden'] = w;
                } else if(c == '|'){
                    curr.ptr ++;
                    if(inner.basic._object_size(res) > 0){
                        conds[conds.length] = res;
                        res = {};
                        w = inner.basic._get_word(curr);
                        if(w != ''){
                            res['tag'] = w;
                        }
                    } else {
                        return false;
                    }
                } else if(inner.basic._is_space_char(c)){
                    ddebug(res, 'res');
                    if(inner.basic._object_size(res) > 0){
                        conds[conds.length] = res;
                    }
                    ddebug('right before');
                    return conds;
                    ddebug('right after');
                } else {
                    return false;
                }
            }

            // end of the line, return the result
            if(inner.basic._object_size(res) > 0){
                conds[conds.length] = res;
            }
            return conds;
        }
    }

    inner.tree = {
        _compile_tree_obj : function (finalInstr, tagStackObj){
            var lastTagLevel = {
                val: 'n'
            }
            for(var k in finalInstr){
                var instr = finalInstr[k];
                switch(instr['type']){
                    case 'tag':
                        inner.tree._push_tag(tagStackObj, instr, lastTagLevel);
                        break
                    case 'html':
                        inner.tree._push_html(tagStackObj, instr);
                        break;
                    case 'attr':
                        inner.tree._push_attr(tagStackObj, instr);
                        break;
                    case 'close':
                        inner.tree._close_tag(tagStackObj, instr, lastTagLevel);
                        break;
                    case 'comment':
                        _push_commet(tagStackObj, instr);
                        break;
                }
            }
        }
        ,
        _push_html: function (tagStackObj, instr){
            if(instr['content'] != null && instr['content'] != ''){
                var s = tagStackObj.stack[tagStackObj.ptr]['content'];
                s[s.length] = instr['content'];
            }
        }
        ,
        _push_attr: function (tagStackObj, instr){
            var currObj = tagStackObj.stack[tagStackObj.ptr];
            if(instr['content'] != null){
                if(instr['attr'] == 'id'){
                    currObj['id'] = instr['content'];
                } else if(instr['attr'] == 'class'){
                    currObj['class'] = {};
                    var classes = instr['content'].split(' ');
                    for(var i in classes){
                        if(classes[i] != ''){
                            currObj['class'][classes[i]] = 1;
                        }
                    }
                } else {
                    currObj['attr'] = currObj['attr'] || {};
                    var attr = currObj['attr'];
                    attr[instr['attr']] = instr['content'];
                }
            }
        }
        ,
        _push_comment: function (tagStackObj, instr){
            if(instr['content'] != null && instr['content'] != ''){
                var content = tagStackObj.stack[tagStackObj.ptr]['content'];
                content[content.length] = ["<!--", instr['content'], "-->"].join('');
            }
        }
        ,
        _close_tag: function (tagStackObj, instr, lastTagLevel){
            if(instr['level'] > 0){
                tagStackObj.ptr -= instr['level'];
                if(tagStackObj.ptr < 0){
                    tagStackObj.ptr = 0;
                }
                lastTagLevel.val = 'n';
            } else {
                for (var i = tagStackObj.ptr; i >= 0; i--){
                    for(var k in instr['cond']){
                        if(typeof(instr['cond'][k]) == 'object' && inner.basic._if_match_close_cond(instr['cond'][k], tagStackObj.stack[i])){
                            tagStackObj.ptr = i - 1 < 0 ? 0 : i - 1;
                            lastTagLevel.val = 'n';
                            return;
                        }
                    }
                }
            }
        }
        ,
        _push_tag: function (tagStackObj, tag, lastTagLevel){
            inner.tree._pop_tag(tagStackObj, tag, lastTagLevel);

            var newTag = tag;
            var content = tagStackObj.stack[tagStackObj.ptr]['content'];
            content[content.length] = newTag;
            tagStackObj.ptr ++;
            tagStackObj.stack[tagStackObj.ptr] = newTag;
            lastTagLevel.val = tag['level'];
        }
        ,
        _pop_tag: function (tagStackObj, tag, lastTagLevel){

            for(var i = 0; i <= tagStackObj.ptr; i++){
                if('cond' in tagStackObj.stack[i]){
                    var conds = tagStackObj.stack[i]['cond'];
                    ddebug('conds', conds['0']);
                    for(var k in conds){
                        ddebug(conds[k], 'tag', tag);
                        if(typeof(conds[k]) ==  'object' && inner.basic._if_match_close_cond(conds[k], tag)){
                            ddebug(conds[k], tag);
                            tagStackObj.ptr = i - 1< 0? 0 : i-1;
                            return;
                        }
                    }
                }
            }

            if(lastTagLevel.val == '1'){
                if(tagStackObj.ptr > 0){
                    tagStackObj.ptr --;
                }
            }
        }
    }

    inner.render = {
        _generate_html: function (treeNodes, htmlText, level, indentation, newline){
        indentation = setDefault(indentation, true);
        newline = setDefault(newline, true);

        if(isArray(treeNodes)){
            for(var k in treeNodes){
                var n = treeNodes[k];
                if(n['type'] == 'tag'){
                    if(indentation)
                        inner.render._print_indentation(level, htmlText);
                    htmlText[htmlText.length] = '<';
                    htmlText[htmlText.length] = n['tag'];
                    if(n['id'] != null){
                        htmlText[htmlText.length] = ' id=\'';
                        htmlText[htmlText.length] = n['id'];
                        htmlText[htmlText.length] = '\'';
                    }
                    if(typeof(n['class']) == 'object'){
                        htmlText[htmlText.length] = ' class=\'';
                        htmlText[htmlText.length] = Object.keys(n['class']).join(' ');
                        htmlText[htmlText.length] = '\'';
                    }
                    if(typeof(n['attr']) == 'object'){
                        for(var attr in n['attr']){
                            htmlText[htmlText.length] = ' ';
                            htmlText[htmlText.length] = attr;
                            htmlText[htmlText.length] = '=\'';
                            htmlText[htmlText.length] = n['attr'][attr];
                            htmlText[htmlText.length] = '\'';
                        }
                        if(n['tag'] == 'input' && n['id'] != null && !('name' in n['attr'])){
                            // pop: if the elem is 'input', set name = id by default. 16/2
                            htmlText[htmlText.length] = ' name=\'';
                            htmlText[htmlText.length] = n['id'];
                            htmlText[htmlText.length] = '\'';
                        }
                    } else if(n['tag'] == 'input' && n['id'] != null){
                        htmlText[htmlText.length] = ' name=\'';
                        htmlText[htmlText.length] = n['id'];
                        htmlText[htmlText.length] = '\'';
                    }
                    htmlText[htmlText.length] = newline? '>\n' : '>';

                    if(n['tag'] == 'link' || n['tag'] == 'meta'){
                        continue;
                    }

                    if(isArray(n['content']) && n['content'].length > 0){
                        inner.tree._push_tag(n['content'], htmlText, level + 1, indentation, newline);
                    }
                    if(indentation)
                        inner.render._print_indentation(level, htmlText);
                    htmlText[htmlText.length] = '</';
                    htmlText[htmlText.length] = n['tag'];
                    htmlText[htmlText.length] = newline? '>\n' : '>';
                } else {
                    if(typeof(n) == 'string' || typeof(n) == 'number'){
                        if(indentation){
                            inner.render._print_indentation(level, htmlText);
                        }
                        htmlText[htmlText.length] = n;
                        if(newline){
                            htmlText[htmlText.length] = '\n';
                        }
                    }
                }
            }
        }
    }
,
    _print_indentation: function (level, htmlText){
        for (i = 0; i < level; i++){
            htmlText[htmlText.length] = '   ';
        }
    }
    }

    function shCreate(){
        var shl = new Object;
        shl['/shobj'] = 1;
        shl['/'] = new Array;
        var content = shl['/'];

        var argv = shCreate.arguments;
        var argc = argv.length;

        for(var i = 0; i < argc; i++){
            content[content.length] = argv[i];
        }
        return shl;
    }

    function shPush(shl){
        if(shl['/shobj'] != 1){
            return false;
        }

        var content = shl['/'];

        var flag = false;
        var argv = shPush.arguments;
        var argc = argv.length;

        for(var i = 0; i < argc; i++){
            if(flag)
                content[content.length] = argv[i];
            else
                flag = true;
        }
        return null;
    }

    function shSet(shl, templateName, subShl){
        shl[templateName] = subShl;
    }

    function shCopy(shl, templateName, subShl){
        shl[templateName] = shClone(subShl);
    }

    function shClone(shl){
        if(!isArray(shl)){
            var newObj = new Object;
        } else{
            newObj = new Array;
        }


        for(var i in shl){
            if(typeof(shl[i]) != 'object'){
                newObj[i] = shl[i];
            } else {
                newObj[i] = shClone(shl[i]);
            }
        }
        return newObj;
    }

    function shHtml(shl, indentation, newline){
        indentation = setDefault(indentation, true);
        newline = setDefault(newline, true);
        ddebug(shl);

        if(shl['/shobj'] == 1){
            var compiledInstr = [];
            var r = inner.basic._parse_shl_code(compiledInstr, shl['/'], shl, indentation, newline);
            if(r != null){
                alert(r);
                return '';
            }
            ddebug(compiledInstr, 'compiled instr');

            var tagStackObj = {
                stack:[{
                    content:[]
                }],
                ptr:0
            }
            r = inner.tree._compile_tree_obj(compiledInstr, tagStackObj);
            if(r != null){
                return '';
            }
            delete finalInstr;

            var htmlText = [];
            r = inner.tree._push_tag(tagStackObj.stack[0]['content'], htmlText, 0, indentation, newline)
            if(r != null){
                return '';
            }
            delete tagStackObj;

            return htmlText.join('');
        } else {
            if (typeof(shl) == 'string'){
                return shl;
            } else {
                return '';
            }
        }

    }


    function shQuick(){
        var argv = shQuick.arguments;
        var argc = argv.length;
        var funcArgv = [];

        for(var i = 0; i < argc; i++){
            funcArgv[funcArgv.length] = argv[i];
        }

        return shHtml(shCreate(funcArgv));
    }

    // ---------------------------- shl util functions





    // ----------------------------- first run : parsing shl

    

    // ------------------------------------- second run : compiling tree object

    

    // ---------------------------- third run : generating html text

    

    Object.keys = Object.keys || function(o) {
        var result = [];
        for(var name in o) {
            if (o.hasOwnProperty(name))
                result.push(name);
        }
        return result;
    }



    shl.fn = shl.prototype = {
        init: function(){
            var argv = this.init.arguments;
            for(var i = 0; i < argv.length; i++){
                alert(argv[i]);
            }
        }
        ,
        html: function(data){

        }
        ,
        push: function(){

        }

    }

    shl.fn.init.prototype = shl.fn;
    window.shl = shl;

})(window)


$().ready(initPage)

function initPage(){

}